<!--
 * @description 组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<view
		class="pure-circle-progress"
		:class="_classes"
		:style="_styles"
	>
		<canvas
			class="pure-circle-progress__canvas"
			:canvas-id="canvasId"
			:id="canvasId"
		></canvas>

		<!-- 进度值 -->
		<view
			class="pure-circle-progress__pivot"
			v-if="showPivot || $slots.default"
		>
			<slot :percent="_ani.now"> {{ _pivotText }} </slot>
		</view>
	</view>
</template>

<script>
	import commonComponentOptions from "../../config/options";
	export default {
		options: commonComponentOptions
	};
</script>

<script setup>
	import { ref, computed, onMounted, getCurrentInstance, watch } from "vue";
	import props from "./props";
	import { generateUUID, rpx2px, delay, isRpx } from "@/uni_modules/pure-utils";

	// -------------------------------------------------------------------------------- Refs
	const canvasId = ref(generateUUID());
	const instance = getCurrentInstance();
	let _ctx = uni.createCanvasContext(canvasId.value, instance.proxy);

	// 动画相关数据
	const _ani = ref({
		animating: false, // 动画状态
		from: 0, // 开始进度
		to: 0, // 目标进度
		now: 0 // 当前进度
	});

	// xi进度值文本
	const _pivotText = computed(() => {
		if (_props?.pivotText) return _props.pivotText;
		const now = _ani.value.now.toFixed?.(2);
		// 舍弃小数末尾的0
		return now.replace(/\.?0+$/, "") + "%";
	});

	// -------------------------------------------------------------------------------- Props
	const _props = defineProps(props);

	// -------------------------------------------------------------------------------- Emits
	const _emits = defineEmits([]);

	// -------------------------------------------------------------------------------- Classes
	const _classes = computed(() => {
		const array = [];
		return array;
	});

	// -------------------------------------------------------------------------------- Styles
	const _styles = computed(() => {
		const array = [];

		// 大小
		if (_props.size) array.push(`--pure-circle-progress-size: ${_props.size}`);

		// 环的宽度
		if (_props.strokeWidth) array.push(`--pure-circle-progress-stroke-width: ${_props.strokeWidth}`);

		// 底环颜色
		if (_props.inactiveColor) array.push(`--pure-circle-progress-inactive-color: ${_props.inactiveColor}`);

		// 进度
		if (_ani.value.now > 0) array.push(`--pure-circle-progress-value: 1`);
		else array.push(`--pure-circle-progress-value: 0`);

		return array;
	});

	// 进度值变化时
	watch(
		() => _props.percent,
		(newVal, oldVal) => {
			// 实时更新
			_animate(oldVal, newVal);
		}
	);

	// 数据变化后从新绘制
	watch(
		[() => _props.size, () => _props.strokeWidth, () => _props.inactiveColor, () => _props.activeColor],
		(newVal, oldVal) => {
			_animate(0, _props.percent);
		}
	);

	onMounted(async () => {
		_animate(0, _props.percent);
	});

	// 绘制进度条
	function _drawProgress(progress = 0) {
		progress = Number(progress);

		// 圆的直径
		const diameter = isRpx(_props.size) ? parseFloat(rpx2px(_props.size)) : parseFloat(_props.size);

		// 圆的中心点
		const center = diameter / 2;

		// 环的宽度
		const strokeWidth = isRpx(_props.strokeWidth)
			? parseFloat(rpx2px(_props.strokeWidth))
			: parseFloat(_props.strokeWidth);

		// 底色
		const inactiveColor = _props.inactiveColor;

		// 进度条颜色
		const activeColor = progress > 0 ? _props.activeColor : _props?.zeroDot ? _props.activeColor : "rgba(0,0,0,0)";

		// 圆的半径
		const radius = diameter / 2 - strokeWidth / 2;

		// 进度条弧度
		const radian = (progress / 100) * 2 * Math.PI;

		// 绘制底色
		_ctx.setLineWidth(strokeWidth);
		_ctx.setStrokeStyle(inactiveColor);
		_ctx.beginPath();
		_ctx.arc(center, center, radius, 0, 2 * Math.PI);
		_ctx.stroke();

		// 绘制进度条
		_ctx.setLineWidth(strokeWidth);
		_ctx.setStrokeStyle(activeColor);
		_ctx.setLineCap("round");
		_ctx.beginPath();
		_ctx.arc(center, center, radius, 0, radian);
		_ctx.stroke();
		_ctx.draw();
	}

	// 动画
	async function _animate(start = 0, end = 0) {
		// 动画进行中
		if (_ani.value.animating) {
			// 开始进度设置为动画进行到的进度
			_ani.value.from = _ani.value.now;
			_ani.value.to = end;
		}

		// 动画未进行中
		else {
			_ani.value.from = start;
			_ani.value.to = end;
			_ani.value.now = start;
		}

		// 动画更新
		async function update() {
			// 间隔多久更新一下
			let milliseconds = 20;

			// 绘制次数
			let count = 20;

			// 支付宝小程序绘制的慢
			// #ifdef MP-ALIPAY
			milliseconds = 40;
			count = 1;
			// #endif

			// 每 N 毫秒的增量
			const increment = (_ani.value.to - _ani.value.from) / count;

			// 本次目标进度
			let targetProgress = _ani.value.now + increment;

			// 判断本次目标进度是否超出整体进度
			if (
				(increment >= 0 && targetProgress >= _ani.value.to) ||
				(increment <= 0 && targetProgress <= _ani.value.to)
			) {
				_ani.value.from = _ani.value.to;
				_ani.value.now = _ani.value.to;
			} else {
				_ani.value.now = targetProgress;
			}

			// 绘制进度条
			_drawProgress(_ani.value.now);

			// 判断是否到达目标进度
			if (_ani.value.now == _ani.value.to) {
				_ani.value.animating = false;
				return;
			}

			// 未到达目标进度，等待一下，继续更新
			await delay(milliseconds);
			update();
		}

		// 默认执行一次更新
		if (!_ani.value.animating) {
			_ani.value.animating = true;
			update();
		}
	}
</script>

<style scoped lang="scss">
	@import "./style.scss";
</style>
